import * as nodeCron from 'node-cron';
import Job from '@/models/monitor/job.model';
import JobLog from '@/models/monitor/job-log.model';
import { getLogger } from '@/utils/logger';

// 创建scheduler专用日志记录器
const logger = getLogger('scheduler-util');

// 定义node-cron的ScheduleOptions接口
interface ScheduleOptions {
  scheduled?: boolean;
  timezone?: string;
  recoverMissedExecutions?: boolean;
}

/**
 * 定时任务工具类
 */
class SchedulerUtils {
  // 存储运行中的任务
  private static tasks = new Map<string, nodeCron.ScheduledTask>();

  // 任务执行限制映射（用于禁止并发）
  private static concurrentLimits = new Map<string, boolean>();

  // 白名单前缀（定义允许执行的任务目标前缀）
  private static readonly whiteListPrefixes = [
    'system.task.',
    'monitor.task.',
    'tool.task.',
    'ryTask.'
  ];

  /**
   * 判断目标字符串是否在白名单中
   * @param invokeTarget 调用目标字符串
   * @returns 是否在白名单中
   */
  public static whiteList(invokeTarget: string): boolean {
    if (!invokeTarget || typeof invokeTarget !== 'string') {
      return false;
    }

    return this.whiteListPrefixes.some(prefix => invokeTarget.startsWith(prefix));
  }

  /**
   * 初始化任务
   * @param job 任务信息
   */
  public static async createScheduleJob(job: Job): Promise<void> {
    if (!job || !job.cronExpression || job.status === '1') {
      return;
    }

    const jobKey = job.getJobKey();

    // 检查任务是否已存在
    if (this.tasks.has(jobKey)) {
      this.tasks.get(jobKey)?.stop();
      this.tasks.delete(jobKey);
    }

    try {
      // 创建定时任务
      const task = nodeCron.schedule(job.cronExpression, async () => {
        await this.executeJob(job);
      }, {
        scheduled: true
      } as ScheduleOptions);

      // 存储任务实例
      this.tasks.set(jobKey, task);
      logger.info(`创建定时任务成功: ${jobKey}, cron: ${job.cronExpression}`);
    } catch (error) {
      logger.error(`创建定时任务失败: ${jobKey}`, { error, stack: error instanceof Error ? error.stack : undefined });
    }
  }

  /**
   * 执行任务
   * @param job 任务信息
   * @returns 执行结果
   */
  public static async executeJob(job: Job): Promise<boolean> {
    const jobKey = job.getJobKey();
    if (job.concurrent === '1') {
      if (this.concurrentLimits.get(jobKey)) {
        logger.info(`跳过并发执行的任务: ${jobKey}`, { jobId: job.jobId });
        return false;
      }
      this.concurrentLimits.set(jobKey, true);
    }
    const startTime = new Date();
    let status = '0';
    let jobMessage = '';
    let exceptionInfo = '';
    try {
      logger.info(`开始执行任务: ${jobKey}`, { 
        jobId: job.jobId, 
        invokeTarget: job.invokeTarget 
      });
      // 解析invokeTarget
      // 例如 ryTask.ryNoParams 或 ryTask.ryParams('abc')
      const invokeMatch = job.invokeTarget.match(/^(\w+)\.(\w+)(\((.*)\))?$/);
      if (!invokeMatch) throw new Error('invokeTarget格式不正确');
      const [ , moduleName, methodName, , paramStr ] = invokeMatch;
      // 动态import模块
      const modulePath = `@/tasks/${moduleName}`;
      const taskModule = (await import(modulePath)).default;
      if (!taskModule[methodName]) throw new Error(`任务方法不存在: ${methodName}`);
      // 解析参数
      let params: any[] = [];
      if (paramStr) {
        // 支持字符串、数字、布尔、null
        params = paramStr.split(',').map(s => {
          const v = s.trim();
          if (v === 'true') return true;
          if (v === 'false') return false;
          if (v === 'null') return null;
          if (!isNaN(Number(v))) return Number(v);
          // 去除首尾引号
          return v.replace(/^['"]|['"]$/g, '');
        });
      }
      // 执行方法
      await taskModule[methodName](...params);
      jobMessage = '执行成功';
      logger.info(`执行任务成功: ${jobKey}`, { 
        jobId: job.jobId,
        duration: new Date().getTime() - startTime.getTime() 
      });
    } catch (error) {
      status = '1';
      exceptionInfo = error instanceof Error ? error.stack || error.message : String(error);
      jobMessage = '执行失败';
      logger.error(`执行任务失败: ${jobKey}`, { 
        jobId: job.jobId, 
        error, 
        stack: error instanceof Error ? error.stack : undefined 
      });
    } finally {
      if (job.concurrent === '1') {
        this.concurrentLimits.set(jobKey, false);
      }
      try {
        await JobLog.create({
          jobName: job.jobName,
          jobGroup: job.jobGroup,
          invokeTarget: job.invokeTarget,
          status,
          jobMessage,
          exceptionInfo,
          createTime: new Date()
        });
      } catch (error) {
        logger.error(`记录任务日志失败: ${jobKey}`, { 
          jobId: job.jobId, 
          error, 
          stack: error instanceof Error ? error.stack : undefined 
        });
      }
    }
    return status === '0';
  }

  /**
   * 暂停任务
   * @param job 任务信息
   */
  public static pauseJob(job: Job): void {
    const jobKey = job.getJobKey();
    const task = this.tasks.get(jobKey);
    
    if (task) {
      task.stop();
      logger.info(`暂停任务: ${jobKey}`, { jobId: job.jobId });
    }
  }

  /**
   * 恢复任务
   * @param job 任务信息
   */
  public static resumeJob(job: Job): void {
    const jobKey = job.getJobKey();
    const task = this.tasks.get(jobKey);
    
    if (task) {
      task.start();
      logger.info(`恢复任务: ${jobKey}`, { jobId: job.jobId });
    } else {
      // 如果任务不存在，重新创建
      this.createScheduleJob(job);
    }
  }

  /**
   * 删除任务
   * @param job 任务信息
   */
  public static deleteJob(job: Job): void {
    const jobKey = job.getJobKey();
    const task = this.tasks.get(jobKey);
    
    if (task) {
      task.stop();
      this.tasks.delete(jobKey);
      logger.info(`删除任务: ${jobKey}`, { jobId: job.jobId });
    }
  }

  /**
   * 立即执行一次任务
   * @param job 任务信息
   */
  public static async runOnce(job: Job): Promise<boolean> {
    return await this.executeJob(job);
  }

  /**
   * 初始化所有任务，并处理misfire补偿
   */
  public static async initScheduler(): Promise<void> {
    try {
      // 查询所有状态为正常的任务
      const jobs = await Job.findAll({
        where: {
          status: '0'
        }
      });
      for (const job of jobs) {
        // 处理misfire补偿
        await this.handleMisfire(job);
        await this.createScheduleJob(job);
      }
      logger.info(`初始化定时任务完成，共加载 ${jobs.length} 个任务`);
    } catch (error) {
      logger.error('初始化定时任务失败', { 
        error, 
        stack: error instanceof Error ? error.stack : undefined 
      });
    }
  }

  /**
   * 处理misfire补偿逻辑
   * @param job 任务信息
   */
  private static async handleMisfire(job: Job): Promise<void> {
    // 仅在服务启动时补偿，且只对misfirePolicy=1/2生效
    if (!job.misfirePolicy || job.misfirePolicy === '0' || job.misfirePolicy === '3') return;
    // 获取上次执行时间（用updateTime或createTime）
    const lastTime: Date = job.updateTime || job.createTime || new Date();
    const now = new Date();
    // 计算所有错过的触发点
    const cronParser = require('cron-parser');
    let missedTimes: Date[] = [];
    try {
      const interval = cronParser.parseExpression(job.cronExpression, { currentDate: lastTime, endDate: now });
      while (true) {
        const next = interval.next();
        if (next.getTime() >= now.getTime()) break;
        missedTimes.push(new Date(next));
        // misfirePolicy=2只补偿一次
        if (job.misfirePolicy === '2') break;
      }
    } catch (e) {
      // 解析异常忽略
      logger.warn(`解析cron表达式出错: ${job.cronExpression}`, { 
        jobId: job.jobId, 
        error: e, 
        stack: e instanceof Error ? e.stack : undefined 
      });
    }
    // misfirePolicy=1补偿所有，2补偿一次
    for (const t of missedTimes) {
      logger.info(`[misfire补偿] 立即补偿执行任务: ${job.getJobKey()}`, { 
        jobId: job.jobId, 
        compensationTime: t.toISOString() 
      });
      await this.executeJob(job);
    }
  }

  /**
   * 清理所有任务
   */
  public static clearJobs(): void {
    this.tasks.forEach((task, key) => {
      task.stop();
      logger.info(`停止任务: ${key}`);
    });
    
    this.tasks.clear();
    this.concurrentLimits.clear();
    logger.info('所有定时任务已清理');
  }
}

export default SchedulerUtils; 